package org.dromara.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ijpay.core.kit.WxPayKit;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.exception.BusinessException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.constant.MachineConstant;
import org.dromara.system.domain.SimMallCommodity;
import org.dromara.system.domain.SimMallOrder;
import org.dromara.system.domain.SimUserLevel;
import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.bo.InitPaySimOrderBo;
import org.dromara.system.domain.bo.SimMallOrderBo;
import org.dromara.system.domain.bo.SimUserPurseBo;
import org.dromara.system.domain.bo.UserLevelBo;
import org.dromara.system.domain.vo.SimMallOrderVo;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.enums.MallOrderStatusEnum;
import org.dromara.system.enums.PayTypeEnum;
import org.dromara.system.enums.QueryTypeEnum;
import org.dromara.system.enums.SysUserProfitRecordsEnum;
import org.dromara.system.mapper.SimMallOrderMapper;
import org.dromara.system.mapper.SysUserMapper;
import org.dromara.system.service.*;
import org.dromara.system.service.impl.pay.AbstractPayService;
import org.dromara.system.service.impl.permission.PermissionBaseService;
import org.dromara.system.util.JsonUtil;
import org.dromara.system.util.OrderUtil;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 商城订单Service业务层处理
 *
 * @author Lion Li
 * @date 2025-08-15
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class SimMallOrderServiceImpl extends ServiceImpl<SimMallOrderMapper, SimMallOrder>
    implements ISimMallOrderService {

    public static final String PREFIX = "MALL";
    private final ISimMallCommodityService simMallCommodityService;
    private final PermissionBaseService permissionBaseService;
    private final ISimUserLevelService simUserLevelService;
    private final ISysUserService sysUserService;
    private final ISimUserLevelRecordsService simUserLevelRecordsService;
    private final SysUserMapper sysUserMapper;
    private final ISimUserPurseRecordsService simUserPurseRecordsService;


    @Resource
    private Map<String, AbstractPayService> abstractPayServiceMap;

    /**
     * 查询商城订单
     *
     * @param id 主键
     * @return 商城订单
     */
    @Override
    public SimMallOrderVo queryById(Long id) {
        return baseMapper.selectVoById(id);
    }

    /**
     * 分页查询商城订单列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 商城订单分页列表
     */
    @Override
    public TableDataInfo<SimMallOrderVo> queryPageList(SimMallOrderBo bo, PageQuery pageQuery) {
        permissionBaseService.assignPermission(bo);
        IPage<SimMallOrderVo> page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
        IPage<SimMallOrderVo> list = baseMapper.findAll(page, bo);
        return TableDataInfo.build(list);
    }

    /**
     * 查询符合条件的商城订单列表
     *
     * @param bo 查询条件
     * @return 商城订单列表
     */
    @Override
    public List<SimMallOrderVo> queryList(SimMallOrderBo bo) {
        LambdaQueryWrapper<SimMallOrder> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<SimMallOrder> buildQueryWrapper(SimMallOrderBo bo) {
        LambdaQueryWrapper<SimMallOrder> lqw = Wrappers.lambdaQuery();
        lqw.orderByAsc(SimMallOrder::getId);
        lqw.eq(bo.getUserId() != null, SimMallOrder::getUserId, bo.getUserId());
        lqw.eq(StringUtils.isNotBlank(bo.getOrderNo()), SimMallOrder::getOrderNo, bo.getOrderNo());
        lqw.eq(bo.getCommodityId() != null, SimMallOrder::getCommodityId, bo.getCommodityId());
        lqw.eq(StringUtils.isNotBlank(bo.getLogisticsNo()), SimMallOrder::getLogisticsNo, bo.getLogisticsNo());
        lqw.eq(bo.getNumber() != null, SimMallOrder::getNumber, bo.getNumber());
        lqw.eq(bo.getAmount() != null, SimMallOrder::getAmount, bo.getAmount());
        lqw.eq(bo.getStatus() != null, SimMallOrder::getStatus, bo.getStatus());
        lqw.eq(StringUtils.isNotBlank(bo.getAddress()), SimMallOrder::getAddress, bo.getAddress());
        return lqw;
    }

    /**
     * 新增商城订单
     *
     * @param bo 商城订单
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(SimMallOrderBo bo) {
        SimMallOrder add = MapstructUtils.convert(bo, SimMallOrder.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改商城订单
     *
     * @param bo 商城订单
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(SimMallOrderBo bo) {
        SimMallOrder update = MapstructUtils.convert(bo, SimMallOrder.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(SimMallOrder entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除商城订单信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }


    @Override
    public String createMallOrder(SimMallOrderBo bo) {
        if (ObjectUtil.isNull(bo.getUserId())) {
            bo.setUserId(LoginHelper.getUserId());
        }
        BusinessException.isTrue(ObjectUtil.equal(bo.getUserId(), MachineConstant.ADMIN), "ADMIN禁止下单！");
        String orderNo = OrderUtil.getOrderNo(PREFIX, 10);
        SimMallCommodity simMallCommodity = simMallCommodityService.getById(bo.getCommodityId());
        //校验库存
        BusinessException.isTrue(bo.getNumber() > simMallCommodity.getCommodityStock(), "数量超出库存范围！");
        //校验订单金额
        SysUserVo sysUserVo = sysUserService.selectUserById(bo.getUserId());
        List<SimUserLevel> simUserLevels = simUserLevelService.lambdaQuery().list();
        SimUserLevel simUserLevel = simUserLevels.stream().filter(t2 -> ObjectUtil.equal(t2.getLevelNumber(), sysUserVo.getLevel())).findFirst().orElse(null);
        //单价
        BigDecimal onePrice = NumberUtil.add(simMallCommodity.getCommodityPrice(), Convert.toBigDecimal(simUserLevel.getMallAdd(), BigDecimal.ZERO));
        //总价
        BigDecimal totalAmount = NumberUtil.mul(bo.getNumber(), onePrice);
        boolean amountBool = NumberUtil.equals(bo.getAmount(), totalAmount);
        BusinessException.isFalse(amountBool, "订单金额不一致！");
        SimMallOrderBo simMallOrderBo = SimMallOrderBo.builder()
            .userId(bo.getUserId())
            .orderNo(orderNo)
            .commodityId(bo.getCommodityId())
            .number(bo.getNumber())
            .amount(totalAmount)
            .orderUnitPrice(onePrice)
            .status(MallOrderStatusEnum.UNPAID.getCode())
            .address(bo.getAddress())
            .build();
        insertByBo(simMallOrderBo);

        InitPaySimOrderBo initPaySimOrderBo = InitPaySimOrderBo.builder()
            .simMallOrderBo(simMallOrderBo)
            .openId(bo.getOpenId())
            .build();
        //拉起支付
        AbstractPayService abstractPayService = abstractPayServiceMap.get(
            PayTypeEnum.findOne(bo.getPayType()).getServiceName());
        return abstractPayService.initPaySimOrder(initPaySimOrderBo);
    }

    @Override
    public String wxPayCallback(HttpServletRequest request, HttpServletResponse response) {
        try {
            String xmlMsg = readData(request);
            log.info("支付订单回调返回{}", JsonUtil.toJSONString(xmlMsg));
            Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);
            log.info("支付订单回调返回转json{}", JsonUtil.toJSONString(params));
            String returnCode = params.get("return_code");
            if (WxPayKit.codeIsOk(returnCode) && WxPayKit.codeIsOk(returnCode)) {
                Long attach = Convert.toLong(params.get("attach"));
                SimMallOrder simMallOrder = lambdaQuery().eq(SimMallOrder::getId, attach).one();
                if (ObjectUtil.isNotNull(simMallOrder)
                    && ObjectUtil.equal(simMallOrder.getStatus(), MallOrderStatusEnum.UNPAID.getCode())) {
                    dealMallOrderWork(simMallOrder);
                }
                Map<String, String> xml = new HashMap<String, String>(2);
                xml.put("return_code", "SUCCESS");
                xml.put("return_msg", "OK");
                return WxPayKit.toXml(xml);
            }
        } catch (Exception e) {
            log.info("微信支付回调失败：{}", e.toString());
        }
        Map<String, String> xml = new HashMap<String, String>(2);
        xml.put("return_code", "FAIL");
        xml.put("return_msg", "");
        return WxPayKit.toXml(xml);
    }

    public void dealMallOrderWork(SimMallOrder simMallOrder) {
        SysUserVo sysUserVo = sysUserService.selectUserById(simMallOrder.getUserId());
        //变为待发货
        lambdaUpdate().set(SimMallOrder::getStatus, MallOrderStatusEnum.PENDING_SHIPMENT.getCode())
            .eq(SimMallOrder::getId, simMallOrder.getId())
            .update();
        //更改商品库存
        SimMallCommodity simMallCommodity = simMallCommodityService.getById(simMallOrder.getCommodityId());
        simMallCommodityService.lambdaUpdate()
            .set(SimMallCommodity::getCommodityStock, simMallCommodity.getCommodityStock() - simMallOrder.getNumber())
            .eq(SimMallCommodity::getId, simMallOrder.getCommodityId())
            .update();
        List<SimUserLevel> list = simUserLevelService.lambdaQuery().orderByDesc(SimUserLevel::getBuySimNum).list();
        List<SysUser> upUserList = permissionBaseService.findUpUserList(simMallOrder.getUserId(), QueryTypeEnum.ALL.getCode());
        upUserList.forEach(t -> {
            //Admin不参与升级
            if (!ObjectUtil.equal(t.getUserId(), MachineConstant.ADMIN)) {
                List<Long> user = permissionBaseService.findUser(t, QueryTypeEnum.ALL.getCode());
                List<SimMallOrderVo> upgradeOrder = baseMapper.findUpgradeOrder(user);
                // 使用 Stream 计算总数量
                int totalNum = upgradeOrder.stream()
                    .mapToInt(SimMallOrderVo::getNumber)
                    .sum();

                SimUserLevel simUserLevel = list.stream()
                    .filter(t2 -> totalNum >= t2.getBuySimNum()).findFirst().orElse(null);
                if (t.getLevel() < simUserLevel.getLevelNumber()) {
                    //升级
                    UserLevelBo build = UserLevelBo.builder()
                        .userId(sysUserVo.getUserId())
                        .levelNum(simUserLevel.getLevelNumber())
                        .remark(simMallOrder.getOrderNo() + "，截止购买数量=" + totalNum).build();
                    simUserLevelRecordsService.updateUserLevel(build);
                }
            }
        });
        //分润  //计算本单分润
        BigDecimal profit = NumberUtil.mul(NumberUtil.sub(simMallOrder.getOrderUnitPrice(), simMallCommodity.getCommodityPrice()), simMallOrder.getNumber());
        //给上级
        SimUserPurseBo sysUserPurseBo = SimUserPurseBo.builder()
            .userId(sysUserVo.getPId())
            .type(SysUserProfitRecordsEnum.MALL_PROFIT.getCode())
            .profit(profit)
            .remark(simMallOrder.getOrderNo())
            .build();
        simUserPurseRecordsService.updateUserPurse(CollUtil.newArrayList(sysUserPurseBo));
    }




    public String readData(HttpServletRequest request) {
        BufferedReader br = null;
        try {
            StringBuilder result = new StringBuilder();
            br = request.getReader();
            for (String line; (line = br.readLine()) != null; ) {
                if (result.length() > 0) {
                    result.append("\n");
                }
                result.append(line);
            }
            return result.toString();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
